package com.bblocks.common.anti_reptile.data;

import com.bblocks.common.anti_reptile.config.AntiReptileProperties;
import com.bblocks.common.anti_reptile.constant.AntiReptileConsts;
import com.bblocks.common.anti_reptile.module.IpUserNumVo;
import com.bblocks.common.anti_reptile.module.RuleStatVO;
import com.bblocks.common.anti_reptile.rule.RuleData;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.RestHighLevelClient;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;


import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

/**
 * <p>Project: bb-anti-reptile - PlumelogDataStat</p>
 * <p>描述：统计各种请求数据
 * 1、用户数据：用户X接口日最大qps（24小时内最高的qps），然后日中位数/平均值（目前采用中位数）
 *      例如:x1接口user1： 20--即非登录最大qps20，(user_per_qps=20)
 *            接口user2： 30--即非登录最大qps30，(user_per_qps=30)
 *            接口user3： 40--即非登录最大qps40，(user_per_qps=40)
 *      然后取20,30,40 中位数=30（avg，max都为此值）
 * 2、ip数据：ip非登录X接口最大qps（24小时内最高的qps）/本IP用户数，然后全部IP x接口日中位数/平均值（目前采用中位数）（登录用户必须 >= 1，不足1的按1计算）
 *     例如:x1接口ip1： 25/2=12.5--即非登录最大qps25，总共有2个用户，即为：12.5次/人/ip(ip_per_qps=12.5)
 *           接口ip2： 30/3=12.5--即非登录最大qps30，总共有3个用户，即为：10次/人/ip(ip_per_qps=10)
 *           接口ip3： 30/0=30--即非登录最大qps30，总共有0个用户-按1计算，即为：30次/人/ip(ip_per_qps=30)
 *     然后取30,12.5,10 中位数=12.5（avg，max都为此值）
 *
 * 3、以上只是单日，7天数据使用再次中位数，计算得出ip/用户的接口：均值访问，最大qps
 * 4、qps可以按5秒计算，最终转化成1秒qps。
 * 5、以上统计可以优化，以计算出，ip/user avg，和max后续将以此值来控制入口的流量
 * </p>
 *
 *Plumelog数据结构：
 * plume_log_run_20240325
 * URL（访问url），USER_ID(用户ID)，appName（应用名称-为了提取user_id,本次数据统计不从gw提取），TOKEN，IP(ip)，COST(耗时)，REQ_FROM(来源，应用调用来源)，dtTime（date 时间）
 *
 *
 * @Author Zhao [125043150@qq.com]
 * @Date 2024/3/25 11:47
 * @Version 1.0
 * @since 8
 */
@ConditionalOnClass({ RedissonClient.class, RestHighLevelClient.class})
@Slf4j
//@Component
public class PlumelogDataStat {
    @Resource
    @Qualifier(AntiReptileConsts.ES_CLIENT_ANTI)
    private RestHighLevelClient client;
    @Resource
    private RuleData ruleData;
    @Resource
    private AntiReptileProperties antiReptileProperties;

    Timer timer = new Timer();

    /**
     * 启动定时器-（加锁-定时提取数据）
     */
    @PostConstruct
    public void init() {
        //启动线程，提取并计算数据
        log.info("启动线程定时抓取访问数据！");
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                try{
                    allDatas();
                }catch (Exception e){
                    log.error("提取数据失败：",e);
                }
            }
        }, getRunStartTime(this.antiReptileProperties), 24*60*60*1000);//2*1000, 5*1000
    }

    @PreDestroy
    public void destroy() {
        timer.cancel();
    }


    private void allDatas(){
        log.info("提取流量控制数据！");
        //提取数据
       List<RuleStatVO> plumelogIps = queryIpDatas();
       plumelogIps.forEach(vo->{
           ruleData.saveRule(vo);
       });
       List<RuleStatVO> plumelogUsers =  queryIpDatas();
        plumelogUsers.forEach(vo->{
            ruleData.saveRule(vo);
        });
        List<IpUserNumVo> plumelogIUserNums = queryIpUserNums();
        plumelogIUserNums.forEach(vo->{
            ruleData.saveIpUser(vo);
        });

        //加点测试数据吧
        /*
        log.info("测试加点数据！");
        Random r = new Random();
        RuleStatVO ruleStatVO = RuleStatVO
                .builder()
                //.url("/standard/area/detailsByCode/340000"+r.nextInt(10))
                .url("/area/detailsByCode/340000")
                .rateAvgIp(2)
                .rateMaxIp(20+r.nextInt(10))
                //.rateMaxIp(2 + 1)
                .rateAvgUser(3)
                .rateMaxUser(2+r.nextInt(5))
                //.rateMaxUser(3 + 1)
                .build();
        log.info("ruleStatVO:{}",ruleStatVO);
        ruleData.saveRule(ruleStatVO);

        IpUserNumVo ipUserNumVo = IpUserNumVo.builder()
                .ip("127.0.0.1")
                .userNum(r.nextInt(3))
                //.userNo(1)
                .build();
        log.info("ipUserNoVo:{}", ipUserNumVo);
        ruleData.saveIpUser(ipUserNumVo);*/
    }

    /**
     * 统计ip的（近7天吧），接口
     */
    public List<RuleStatVO> queryIpDatas(){
        log.info("暂时未实现es的数据ip统计。。。");
        return new ArrayList<>(0);
    }

    /**
     * 统计用户的
     */
    public List<RuleStatVO> queryUserDatas(){
        log.info("暂时未实现es的数据user统计。。。");
        return new ArrayList<>(0);
    }

    public List<IpUserNumVo> queryIpUserNums(){
        log.info("暂时未实现es的数据ip 会员数统计。。。");
        return new ArrayList<>(0);
    }

   /* public List<RuleStatVO> queryUserDatas(){

        //在BoolQueryBuilder 对象设置查询条件，以下的逻辑是name=张三 and (title like '%重要%' or content = '程序员')
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.termQuery("name", "张三"));
        BoolQueryBuilder shouldQuery = new BoolQueryBuilder();
        shouldQuery.should(QueryBuilders.wildcardQuery("title", "*重要*"));
        shouldQuery.should(QueryBuilders.matchPhraseQuery("content", "程序员"));
        boolQueryBuilder.must(shouldQuery);
        //在SearchSourceBuilder 对象设置分页/排序/高亮,下面的逻辑是根据创建时间倒序，current为当前页，size为每页条数
        SearchSourceBuilder query = new SearchSourceBuilder().query(boolQueryBuilder);
        query.sort("createTime", SortOrder.DESC);
        query.from((current > 0 ? (current - 1) : 0) *size);
        query.size(size);
        SearchRequest searchRequest = new SearchRequest(INDEX).source(query);
        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);


    }*/

    private void userOneDay(String index,String city) throws IOException {
        /*SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(index);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();


        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                        .must(QueryBuilders.termsQuery("REQ_FROM", "gateway","gateway_inner"))
                        .must(QueryBuilders.existsQuery("URL"))
                        .must(QueryBuilders.existsQuery("USER_ID"))
                        .mustNot(QueryBuilders.termQuery("appName", "bblocks-gateway"));*/



       /* BoolQueryBuilder shouldQuery = new BoolQueryBuilder();
        shouldQuery.should(QueryBuilders.wildcardQuery("title", "*重要*"));
        shouldQuery.should(QueryBuilders.matchPhraseQuery("content", "程序员"));
        boolQueryBuilder.must(shouldQuery);

        TermQueryBuilder termQueryBuilder = QueryBuilders
                .termsQuery("REQ_FROM", "gateway","gateway_inner")
                .termsQuery("city", city);*/

       // searchSourceBuilder.query(boolQueryBuilder);

       /* searchSourceBuilder.from((current > 0 ? (current - 1) : 0) *size);
        searchSourceBuilder.size(size);*/

        //searchRequest.source(searchSourceBuilder);
       // SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);


    }

    private void userOneDay2(String index,String dslJson) throws IOException {
/*        WrapperQueryBuilder wqb = QueryBuilders.wrapperQuery(dslJson);
        SearchResponse searchResponse = client.prepareSearch(basicsysCodeManager.getYjzxYjxxIndex())
                .setTypes(basicsysCodeManager.getYjzxYjxxType())
                .setQuery(wqb)
                .setSize(10).get();*/

/*        String dslJson="{
        "query":{
            "match":{
                "member_id":"17e42e9d73774c0ba5281683861bf1ac"
            }
        },
        "size":1,
                "aggregations":{
            "group_by_field":{
                "terms":{
                    "field":"stat_date",
                            "size":1,
                            "order":[
                    {
                        "_key":"desc"
                    }
                ]
                }
            }
        }
    }";*/

       /* Request request = new Request("GET","/"+index+"/_search");
        request.setJsonEntity(dslJson);
        Response response = client.getLowLevelClient().performRequest(request);
        String responseStr = EntityUtils.toString(response.getEntity());
        System.out.println(responseStr);*/
    }


    /**
     * 获取运行（明天一点）
     * @return
     */
    private Date getRunStartTime(AntiReptileProperties antiReptileProperties){
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);//每天
        //定制每天的01:00:00执行，
        calendar.set(year, month, day, antiReptileProperties.getSyncTime()!=null?antiReptileProperties.getSyncTime() : 1, 00, 00);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date startTime = calendar.getTime();
        log.info("startTime：{}",startTime);
        ;
        return startTime;
    }
}
